package com.kvn.interceptor;

import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.plugin.Invocation;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;

/**
 * Invocation 代理
 * Created by wangzhiyuan on 2018/6/11
 */
public class InvocationProxy {
    private Invocation invocation;
    /**
     * 需要执行的新sql
     */
    private Set<String> newSqlSet;

    public InvocationProxy(Invocation invocation, Set<String> newSqlSet) {
        this.invocation = invocation;
        this.newSqlSet = newSqlSet;
    }

    public Object proceed() throws Throwable {
        List<Object> resultList = new ArrayList<>();

        Object[] args = invocation.getArgs();
        MappedStatement ms = (MappedStatement) args[0]; // statement
        SqlSource sqlSource = ms.getSqlSource();

        // 创建一个SqlSource的Proxy，注入
        for (String newSql : newSqlSet) {
            Object sqlSourceProxy = SqlSourceProxyFactory.getProxy(sqlSource, newSql, ms.getId());
            Field sqlSourceField = ms.getClass().getDeclaredField("sqlSource");
            sqlSourceField.setAccessible(true);
            sqlSourceField.set(ms, sqlSourceProxy);
            Object oneResult;
            try {
                oneResult = invocation.proceed();
            } finally {
                // 调用完之后，要将 sqlSource 还原
                sqlSourceField.set(ms, sqlSource);
            }
            resultList.add(oneResult);
        }

        return mergeResult(resultList);
    }

    /**
     * 合并结果集
     *
     * @param resultList
     * @return
     */
    private Object mergeResult(List<Object> resultList) {
        if (resultList.size() == 1) {
            return resultList.get(0);
        }

        // 将Collection类型的结果集合并
        if (resultList.get(0) instanceof Collection) {
            List finalResult = new ArrayList();
            for (Object result : resultList) {
                finalResult.addAll((Collection) result);
            }
            return finalResult;
        }

        throw new RuntimeException("暂不支持的操作，结果集类型：" + resultList.get(0).getClass());
    }
}
